package com.heiam.search.service.impl;

import com.heiam.search.service.ApSearchService;
import com.heiam.search.service.ApUserSearchService;
import com.heima.model.common.dtos.ResponseResult;
import com.heima.model.common.enums.AppHttpCodeEnum;
import com.heima.model.search.dto.UserSearchDto;
import com.heima.model.user.entity.ApUser;
import com.heima.utils.common.threadUtil.ThreadLocalUtil;
import com.heima.utils.common.threadUtil.UserInfo;
import org.apache.commons.lang.StringUtils;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.common.text.Text;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.SearchHits;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightField;
import org.elasticsearch.search.sort.SortOrder;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import javax.annotation.Resource;
import java.io.IOException;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

@Service
public class ApSearchServiceImpl implements ApSearchService {
    @Resource
    private RestHighLevelClient restHighLevelClient;

    @Resource
    private ApUserSearchService apUserSearchService;
    @Override
    public ResponseResult search(UserSearchDto dto) throws IOException {

        //校验参数
        if(dto==null){
            return ResponseResult.errorResult(AppHttpCodeEnum.PARAM_REQUIRE);
        }

        UserInfo userInfo = ThreadLocalUtil.get();
        //异步调用 保存搜索记录
        if(userInfo!=null&&dto.getFromIndex()==0){
            apUserSearchService.insert(dto.getSearchWords(),userInfo.getId());
        }
        //最小时间检验
        Date minBehotTime = dto.getMinBehotTime();
        minBehotTime=minBehotTime==null?new Date():minBehotTime;


        //每页展示数据条数校验
        int size = dto.getPageSize();
        size=size<=0?10:size;
        //每页最多查询50条
        size=Math.min(size,50);
        //构建请求对象
        SearchRequest request = new SearchRequest("app_article_info");

        //搜索关键词参数
        BoolQueryBuilder boolQuery = QueryBuilders.boolQuery();
        if(StringUtils.isNotEmpty(dto.getSearchWords())){
            boolQuery.must(QueryBuilders.matchQuery("all",dto.getSearchWords()));
        }else{
            boolQuery.must(QueryBuilders.matchAllQuery());
        }
        //发布时间参数
        boolQuery.filter(QueryBuilders.rangeQuery("publishTime").lt(minBehotTime));
        //设置查询条件
        request.source().query(boolQuery);
        //分页
        request.source().from(0).size(size);
        //排序--根据发布时间倒序查询
        request.source().sort("publishTime", SortOrder.DESC);


        //高亮设置
        HighlightBuilder highlightBuilder = new HighlightBuilder();
        highlightBuilder.field("title");
        highlightBuilder.preTags("<font style='color:red; font-size: inherit;'>");
        highlightBuilder.postTags("</font>");
        highlightBuilder.requireFieldMatch(false);
        request.source().highlighter(highlightBuilder);

        //发送请求
        SearchResponse response = restHighLevelClient.search(request, RequestOptions.DEFAULT);

        //解析结果
        SearchHits hits = response.getHits();
        //获取命中数据列表
        SearchHit[] searchHits = hits.getHits();
        List<Map<String, Object>> list = Arrays.stream(searchHits).map(hit -> {
            //获取命中数据原始文档内容
            Map<String, Object> sourceMap = hit.getSourceAsMap();
            sourceMap.put("h_title", sourceMap.get("title"));
            //获取高亮结果集
            Map<String, HighlightField> highlightFields = hit.getHighlightFields();
            if (!CollectionUtils.isEmpty(highlightFields)) {
                //获取指定字段名称的高亮结果
                HighlightField titleFiled = highlightFields.get("title");
                //判断对应字段的结果集是否为空
                if (titleFiled != null) {
                    //获取高亮文本端
                    Text[] texts = titleFiled.fragments();
                    String hightlightResult = StringUtils.join(texts);
                    //封装高亮文本片段到原始文档
                    sourceMap.put("h_title", hightlightResult);
                }
            }
            return sourceMap;
        }).collect(Collectors.toList());
        return ResponseResult.okResult(list);
    }
}
